package com.atguigu.tingshu.album.service.impl;

import com.atguigu.tingshu.album.mapper.AlbumAttributeValueMapper;
import com.atguigu.tingshu.album.mapper.AlbumInfoMapper;
import com.atguigu.tingshu.album.mapper.AlbumStatMapper;
import com.atguigu.tingshu.album.service.AlbumAttributeValueService;
import com.atguigu.tingshu.album.service.AlbumInfoService;
import com.atguigu.tingshu.common.cache.TsCache;
import com.atguigu.tingshu.common.constant.RedisConstant;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.rabbit.constant.MqConst;
import com.atguigu.tingshu.common.rabbit.service.RabbitService;
import com.atguigu.tingshu.common.result.ResultCodeEnum;
import com.atguigu.tingshu.model.album.AlbumAttributeValue;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.AlbumStat;
import com.atguigu.tingshu.query.album.AlbumInfoQuery;
import com.atguigu.tingshu.vo.album.AlbumAttributeValueVo;
import com.atguigu.tingshu.vo.album.AlbumInfoVo;
import com.atguigu.tingshu.vo.album.AlbumListVo;
import com.atguigu.tingshu.vo.album.AlbumStatVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.Nullable;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;

@Slf4j
@Service
@SuppressWarnings({"all"})
public class AlbumInfoServiceImpl extends ServiceImpl<AlbumInfoMapper, AlbumInfo> implements AlbumInfoService {

    @Autowired
    private AlbumInfoMapper albumInfoMapper;
    @Resource
    private AlbumAttributeValueMapper albumAttributeValueMapper;
    @Resource
    private AlbumStatMapper albumStatMapper;

    @Resource
    private AlbumAttributeValueService albumAttributeValueService;

    @Resource
    private RedisTemplate redisTemplate;

    @Resource
    private RabbitService rabbitService;

    @Resource
    private RedissonClient redissonClient;


    /**
     * 根据专辑id获取专辑统计数据值
     *
     * @param albumId
     * @return
     */
    @Override
    public AlbumStatVo getAlbumStatNum(Long albumId) {
        //调用mapper层方法
        AlbumStatVo albumStatVo = albumStatMapper.selectAlbumStatNum(albumId);
        return albumStatVo;
    }

    /**
     * 根据专辑id查询
     *
     * @param albumId
     * @return
     */
    @TsCache(prefix = "album:",suffix = "info:")
    @Override
    public AlbumInfo getAlbumInfo(Long albumId) {
        //数据库兜底
        return getAlbumInfoFromDb(albumId);
        /**
         * 做优化，先去redis里查找，查不到再去db里查找
         *//*
        //构建redis里的存储key
        String redisKey = RedisConstant.ALBUM_INFO_PREFIX + albumId;
        AlbumInfo albumInfo = null;
        try {
            //去redis中查找
            albumInfo = (AlbumInfo) redisTemplate.opsForValue().get(redisKey);
            //判空
            if (null == albumInfo) {
                System.out.println("缓存没有数据");
                //没说数据，去数据库查
                //加锁
                String lockName = RedisConstant.ALBUM_LOCK_SUFFIX + albumId;
                RLock lock = redissonClient.getLock(lockName);
                //上锁
                lock.lock();
                try {
                    //先判断缓存是否存在
                    albumInfo = (AlbumInfo) redisTemplate.opsForValue().get(redisKey);
                    if (null != albumInfo) return albumInfo;

                    //业务逻辑
                    albumInfo = getAlbumInfoFromDb(albumId);
                    //判断数据库里有没有数据
                    if (null == albumInfo) {
                        //为空，说名数据库也没有
                        //为了防止缓存穿透，设置一个空值
                        redisTemplate.opsForValue()
                                .set(redisKey, new AlbumInfo(), RedisConstant.ALBUM_TEMPORARY_TIMEOUT, TimeUnit.SECONDS);
                        //返回结果
                        return new AlbumInfo();
                    }
                    //数据库里有数据就加到redis中
                    redisTemplate.opsForValue()
                            .set(redisKey, albumInfo, RedisConstant.ALBUM_TIMEOUT, TimeUnit.SECONDS);
                } catch (Exception e) {
                    log.error(e.getMessage(), e);
                } finally {
                    //解锁
                    lock.unlock();
                }
            } else {
                //缓存中有数据
                System.out.println("缓存有数据");
                return albumInfo;
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }*/
    }

    private @Nullable AlbumInfo getAlbumInfoFromDb(Long albumId) {
        //调用mapper层，查询专辑数据
        AlbumInfo albumInfo = albumInfoMapper.selectById(albumId);
        //给albumInfo的albumAttributeValueVoList;赋值。
        //调用mapper层，根据专辑id查询
        //判断是否为空
        if (null != albumInfo) { //nul写前面是为了防止空指针
            //条件查询
            LambdaQueryWrapper<AlbumAttributeValue> listLambdaQueryWrapper = new LambdaQueryWrapper<>();
            listLambdaQueryWrapper.eq(AlbumAttributeValue::getAlbumId, albumInfo.getId());
            List<AlbumAttributeValue> albumAttributeValues = albumAttributeValueMapper
                    .selectList(listLambdaQueryWrapper);
            albumInfo.setAlbumAttributeValueVoList(albumAttributeValues);
        }
        return albumInfo;
    }

    /**
     * 修改专辑信息
     *
     * @param albumId
     * @param albumInfo
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateAlbumInfo(Long albumId, AlbumInfoVo albumInfoVo) {
        //设计两张表的更新操作:album_info,album_attribute_value
        //更新album_info表时，先封装对应的类AlbumInfo
        AlbumInfo albumInfo = new AlbumInfo();
        //进行，信息拷贝
        BeanUtils.copyProperties(albumInfoVo, albumInfo);
        //专辑id
        albumInfo.setId(albumId);
        //调用mapper层的方法
        albumInfoMapper.updateById(albumInfo);
        /**
         * 更新，album_attribute_value的数据，因为前端在修改时没有实时的发送请求
         * 所以在更新时要现根据专辑id删除对应id，再保存新的
         */
        //根据专辑id删除信息
        albumAttributeValueMapper.delete(new LambdaQueryWrapper<AlbumAttributeValue>()
                .eq(AlbumAttributeValue::getAlbumId, albumInfo.getId()));
        //保存信息
        //获取最新的信息
        List<AlbumAttributeValueVo> albumAttributeValueVoList = albumInfoVo.getAlbumAttributeValueVoList();
        //封装AlbumAttributeValue对象
        List<AlbumAttributeValue> albumAttributeValueList = albumAttributeValueVoList.stream()
                .map(albumAttributeValueVo -> {
                    AlbumAttributeValue albumAttributeValue = new AlbumAttributeValue();
                    BeanUtils.copyProperties(albumAttributeValueVo, albumAttributeValue);
                    albumAttributeValue.setAlbumId(albumId);
                    return albumAttributeValue;
                }).collect(Collectors.toList());
        //调用mapper保存
        albumAttributeValueService.saveBatch(albumAttributeValueList);

        //判断专辑是否公开
        if ("1".equals(albumInfo.getIsOpen())) {
            //公开就上架
            rabbitService.sendMessage(MqConst.EXCHANGE_ALBUM, MqConst.ROUTING_ALBUM_UPPER, albumInfo.getId());
            //将专辑id加入布隆过滤器
            RBloomFilter<Object> bloomFilter = redissonClient.getBloomFilter(RedisConstant.ALBUM_BLOOM_FILTER);
            bloomFilter.add(albumInfo.getId());
        } else {
            //没公开就下架
            rabbitService.sendMessage(MqConst.EXCHANGE_ALBUM, MqConst.ROUTING_ALBUM_LOWER, albumInfo.getId());
        }
    }

    /**
     * 删除专辑
     *
     * @param albumId
     */
    @Override
    public void removeAlbumInfo(Long albumId) {
        /**
         * 删除专辑设计删除三张表的数据；album_info，album_attribute_value，album_stat
         */
        //根据专辑id删除专辑信息表的数据
        //调用mapper层
        albumInfoMapper.deleteById(albumId);
        //根据专辑id删除album_attribute_value表的数据
        albumAttributeValueMapper.delete(new LambdaQueryWrapper<AlbumAttributeValue>()
                .eq(AlbumAttributeValue::getAlbumId, albumId));
        //根据专辑id删除album_stat表的信息
        albumStatMapper.delete(new LambdaQueryWrapper<AlbumStat>()
                .eq(AlbumStat::getAlbumId, albumId));
    }

    /**
     * 根据用户id返回对应的专辑信息
     *
     * @param userId
     * @return
     */
    @Override
    public List<AlbumInfo> findUserAllAlbumList(Long userId) {
        //调用mapper方法
        /*List<AlbumInfo> albumInfoList = albumInfoMapper.selectList(new LambdaQueryWrapper<AlbumInfo>()
                .eq(AlbumInfo::getUserId, userId).orderByDesc(AlbumInfo::getId));*/
        LambdaQueryWrapper<AlbumInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(AlbumInfo::getUserId, userId);
        wrapper.orderByDesc(AlbumInfo::getId); //倒序输出
        //数据太多，进行分页处理
        Page<AlbumInfo> page = new Page<>(1, 100);
        Page<AlbumInfo> albumInfoPage = albumInfoMapper.selectPage(page, wrapper);
        //返回结果
        return albumInfoPage.getRecords();
    }

    /**
     * 分页查询专辑列表
     *
     * @param page
     * @param albumInfoVo
     * @return
     */
    @Override
    public IPage<AlbumListVo> findUserAlbumPage(Page<AlbumListVo> page, AlbumInfoQuery albumInfoVo) {
        //调用mapper层的方法
        return albumInfoMapper.selectUserAlbumPage(page, albumInfoVo);
    }

    /**
     * 保存专辑
     *
     * @param albumInfoVo
     * @param userId      专辑对应三张表，所有保存操作要操作三张表分别是：
     *                    album_attribute_value：专辑标签关系表
     *                    album_info：专辑信息表
     *                    album_stat：专辑状态表
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveAlbumInfo(AlbumInfoVo albumInfoVo, Long userId) {
        try {
            //专辑信息表对应的实体类
            AlbumInfo albumInfo = new AlbumInfo();
            //前端传过来的内容跟是：
		/*albumAttributeValueVoList: [
			{attributeId: 1, valueId: 1, valueName: "男频小说"},
			{attributeId: 2, valueId: 4, valueName: "双人"},…]
		0: {attributeId: 1, valueId: 1, valueName: "男频小说"}
		1: {attributeId: 2, valueId: 4, valueName: "双人"}
		2: {attributeId: 3, valueId: 7, valueName: "免费"}
		3: {attributeId: 4, valueId: 8, valueName: "完结"}
		4: {attributeId: 5, valueId: 10, valueName: "新品"}
		albumIntro: "你好"
		albumTitle: "陆小果"
		category3Id: 1018
		coverUrl: "http://192.168.200.130:9000/bjatguiguts/afdca51bc0c64d8ca3bef31fc8fe1839.jpg"
		discount: ""
		isOpen: "1"
		payType: "0101"
		price: ""
		priceType: "0201"
		vipDiscount: ""*/

            //封装albumInfo实体类
            //使用BeanUtils的copyProperties对albumInfo进行赋值
            /**
             * copyProperties，可以给对应的属性赋值，前提是是属性名要相同
             */
            BeanUtils.copyProperties(albumInfoVo, albumInfo);
            //前端没有传userid，自己赋值
            albumInfo.setUserId(userId);
            //设置免费观看的集数，这个只有在是付费的情况下调用
            if (!albumInfo.getPayType().equals(SystemConstant.ALBUM_PAY_TYPE_FREE)) {
                albumInfo.setTracksForFree(5);
            }
            //保存到album_info表zhong
            albumInfoMapper.insert(albumInfo);
            //获取专辑的属性列表
            List<AlbumAttributeValueVo> albumAttributeValueVoList = albumInfoVo.getAlbumAttributeValueVoList();
           /* for (AlbumAttributeValueVo albumAttributeValueVo : albumAttributeValueVoList) {
                //封装专辑属性值javabean
                AlbumAttributeValue albumAttributeValue = new AlbumAttributeValue();
                //插入数据
                albumAttributeValue.setAlbumId(albumInfo.getId());
                albumAttributeValue.setAttributeId(albumAttributeValueVo.getAttributeId());
                albumAttributeValue.setValueId(albumAttributeValueVo.getValueId());

                //调用mapper层保存albumAttributeValue
                albumAttributeValueMapper.insert(albumAttributeValue);
            }*/
            if (!CollectionUtils.isEmpty(albumAttributeValueVoList)) {
                List<AlbumAttributeValue> albumAttributeValues = new ArrayList<>();

                for (AlbumAttributeValueVo albumAttributeValueVo : albumAttributeValueVoList) {
                    AlbumAttributeValue albumAttributeValue = new AlbumAttributeValue();
                    albumAttributeValue.setAlbumId(albumInfo.getId());
                    albumAttributeValue.setAttributeId(albumAttributeValueVo.getAttributeId());
                    albumAttributeValue.setValueId(albumAttributeValueVo.getValueId());
                    albumAttributeValues.add(albumAttributeValue);
                }
                // 批量插入
                albumAttributeValueService.saveBatch(albumAttributeValues);
            }
            //保存专辑状态表
            /**
             *     album_id     '专辑id',
             *     stat_type    '统计类型：0401-播放量 0402-订阅量 0403-购买量 0403-评论数',
             *     stat_num     '统计数目',
             *     create_time  '创建时间
             *     由album_stat表的字段可值，这个表记录的其实是专辑四个属性的数量，所有要一次性存如四条数据
             */
            saveAlbumStat(albumInfo.getId(), SystemConstant.ALBUM_STAT_BROWSE);
            saveAlbumStat(albumInfo.getId(), SystemConstant.ALBUM_STAT_COMMENT);
            saveAlbumStat(albumInfo.getId(), SystemConstant.ALBUM_STAT_PLAY);
            saveAlbumStat(albumInfo.getId(), SystemConstant.ALBUM_STAT_SUBSCRIBE);

            //判断专辑是否公开
            if ("1".equals(albumInfo.getIsOpen())) {
                //公开就上架
                rabbitService.sendMessage(MqConst.EXCHANGE_ALBUM, MqConst.ROUTING_ALBUM_UPPER, albumInfo.getId());
            }
        } catch (BeansException e) {
//            e.printStackTrace();
            //打印日志
            log.error(e.getMessage(), e);
            //抛出指定异常
            throw new GuiguException(ResultCodeEnum.SERVICE_ERROR);

        }
    }

    public void saveAlbumStat(Long albumId, String statType) {
        //封装数据
        AlbumStat albumStat = new AlbumStat();
        albumStat.setAlbumId(albumId);
        albumStat.setStatType(statType);
        albumStat.setStatNum(new Random().nextInt(100000));
        //调用mapper保存albumStat
        albumStatMapper.insert(albumStat);
    }
}
